package com.stone.design.mode.strategy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 扫描带有自定义注解@CodeType，取得value，然后放入容器中
 *
 * @author 文攀 Mr_wenpan@163.com 2020-06-19 16:28
 **/
@Component
public class CodeTypeHandlerContext implements ApplicationContextAware {

    @Autowired
    ApplicationContext applicationContext;

    /**
     * key为codeType，value为class
     * 存放编码code和对应的策略，可以通过不同的编码取得不同的策略
     * map容器定义为全局静态的的
     * Class：可以存放多种类，也可以写成某种类型接口形式，这样下面直接get返回
     * 就好了，不用再applicationContext.getBean(clazz)
     */
    private static final Map<String, Class<?>> HANDLER_MAP = new HashMap<>(32);

    /**
     * 外部需要做if--else判断的方法中，
     * 只要传入对应的参数调用该方法即可获取到对应的策略
     *
     * @param payType 支付类型
     * @return 推送策略
     */
    public PushStrategy getHandlerInstance(String payType) {

        // 取得对应策略的Class类对象
        Class<?> clazz = HANDLER_MAP.get(payType);
        if (clazz == null) {
            throw new RuntimeException("没有合适的处理策略");
        }
        // 通过Class信息去容器中取出一个对象
        return (PushStrategy) applicationContext.getBean(clazz);
    }

    /**
     * 重写setApplicationContext方法，然后扫描带有自定义注解@CodeType的Bean，然后存储起来，方便Service的获取。
     *
     * @param applicationContext 容器上下文
     * @throws BeansException 异常
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        // 遍历带有CodeType注释的类
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(CodeType.class);
        if (beans.size() > 0) {
            for (Object serviceBean : beans.values()) {
                // 取得注解的CodeType值，将该值与对应的策略放入到map容器
                String payType = serviceBean.getClass().getAnnotation(CodeType.class).value();
                HANDLER_MAP.put(payType, serviceBean.getClass());
            }
        }

    }
}